# -*- coding: utf-8 -*-

"""
Module Description:活动商城管理
Date: 2021/3/8
Author: HuYuanCheng
"""
from collections import defaultdict

from app.area.core.component_center import ComponentCenter
from pyshare.const.enums.item import ItemType
from pyshare.const.enums.welfare import ShopLimitType
from pyshare.const.lang.tips_info import TipsInfo
from pyshare.dal.repository_impl import ActivityShopRecordRepository, CrossMonopolyRoleRepository, \
    CrossMonopolyShopCfgRepository
from pyshare.dal.repository_impl.puzzle_repository import PuzzleShopCfgRepository, PuzzleRoleRepository
from pyshare.framework.dal.dal_manager import TransactionDelegator
from pyshare.framework.error_handle import GameException
from pyshare.game_logs.puzzle_log import PuzzleLog
from pyshare.utils.game_log.game_log_define import PuzzleScoreLog
from pyshare.utils.game_log.log_param import LogParam
from pyshare.utils.time_utils import isPassDay, getCT, getDaysCountdown


class ActivityShopManager(object):
    """
    活动商店管理
    商城内的商城配置必须分别配置限购类型，可以针对每个商品做不同类型的限购（每日or活动）。
    每个商品必须配单列表
    """

    def __init__(self, activity_role, shop_cfg_list):
        self.activity_role = activity_role
        self.activity_id = activity_role.activity_id
        self.rid = activity_role.role_guid
        self.cc = ComponentCenter()
        # 商城配置字典
        self.product_cfg_dict = self.get_product_cfg_dict(shop_cfg_list)
        # 每日刷新商品配置列表
        self.day_limit_list = self.get_limit_cfg_list(shop_cfg_list)

        # 刷新限购
        self.refresh_limit()

    @staticmethod
    def get_limit_cfg_list(shop_cfg_list):
        """
        获得每日刷新商品配置列表
        活动商城限购类型：0-活动限购（即总限购，不需要重置），1-每日限购（每日重置）
        :param shop_cfg_list:
        :return:
        """
        # 每日限购字典
        cfg_dict = defaultdict(list)
        for c in shop_cfg_list:
            cfg_dict[c.limit_type].append(c.product_id)
        day_limit_list = cfg_dict[ShopLimitType.Day]

        return day_limit_list

    @staticmethod
    def get_product_cfg_dict(shop_cfg_list):
        """
        获得商品配置字典
        :param shop_cfg_list:
        :return:
        """
        # 商品配置字典
        product_cfg_dict = {}
        for c in shop_cfg_list:
            product_cfg_dict[c.product_id] = c

        return product_cfg_dict

    def refresh_limit(self):
        """刷新限购次数"""
        shop_role_records = self.get_role_shop_records()
        for r in shop_role_records:
            if isPassDay(r.last_buy_time):
                # 是否跨天
                ActivityShopRecordRepository.update_buy_num_by_activityid_rid_productidlist(
                    activity_id=self.activity_id,
                    rid=self.rid,
                    buy_num=0,
                    product_id_list=self.day_limit_list)
                r.last_buy_time = getCT()
                ActivityShopRecordRepository.save(r)

    def get_role_shop_records(self):
        """获取角色商城购买记录"""
        return ActivityShopRecordRepository.filter_by_activityid_rid(self.activity_id, self.rid)

    def check_is_can_buy(self, product_cfg, count):
        """
        校验是否能购买
        :return:
        """
        return

    @staticmethod
    def check_buy_limit(product_record, product_cfg, count):
        """
        校验限购
        :return:
        """
        return

    def validate_product_purchase(self, product_cfg, count):
        """
        购买校验
        :param product_cfg:
        :param count:
        :return:
        """
        product_id = product_cfg.product_id
        # 校验是否能购买
        self.check_is_can_buy(product_cfg, count)

        product_record = ActivityShopRecordRepository.get_by_activityid_rid_productid(self.activity_id, self.rid,
                                                                                      product_id)
        if not product_record:
            product_record = ActivityShopRecordRepository.create(self.activity_id, self.rid, product_id)

        # 校验限购
        self.check_buy_limit(product_record, product_cfg, count)

        return product_record

    def reduce_cost(self, product_cfg, count):
        """
        扣除兑换道具（需重写，扣除对应数值或对应道具）
        :param product_cfg:
        :param count:
        :return:
        """
        return

    @staticmethod
    def get_award_item_list(product_cfg):
        """
        获得购买道具（需重写,并返回二维道具列表）
        :param product_cfg:
        :return:
        """
        return []

    def purchase_log(self, product_cfg, count):
        """
        埋点
        :param product_cfg:
        :param count:
        :return:
        """
        return

    def purchase_shop_product(self, product_id, count, remark):
        """购买商店物品"""
        product_cfg = self.product_cfg_dict.get(product_id, None)
        if not product_cfg:
            raise GameException(TipsInfo.RoleKeys.configError)

        # 校验
        product_record = self.validate_product_purchase(product_cfg, count)

        with TransactionDelegator():
            # 扣除兑换道具
            self.reduce_cost(product_cfg, count)
            # 获得道具
            award_item_list = self.get_award_item_list(product_cfg)
            award_list = [[award_item[0], award_item[1], award_item[2] * count] for award_item in award_item_list]
            goods = self.cc.goods.award_many_goods(self.rid, award_list,
                                                   LogParam(rid=self.rid, remark=remark))
            # 更新购买记录
            product_record.buy_num += count
            product_record.last_buy_time = getCT()
            ActivityShopRecordRepository.save(product_record)

        # 埋点
        self.purchase_log(product_cfg, count)

        return goods, product_record


class CrossMonopolyShop(ActivityShopManager):
    """大富翁活动商城"""

    def __init__(self, monopoly_role, activity):
        super(CrossMonopolyShop, self).__init__(
            activity_role=monopoly_role,
            shop_cfg_list=CrossMonopolyShopCfgRepository.filter_by_templateid(activity.template_id)
        )
        self.repository = CrossMonopolyRoleRepository

    def reduce_cost(self, product_cfg, count):
        """
        扣除兑换券
        :param product_cfg:
        :param count:
        :return:
        """
        self.activity_role.coin -= product_cfg.cost_num * count
        self.repository.save(self.activity_role)

    def check_is_can_buy(self, product_cfg, count):
        """
        校验是否能购买
        :param product_cfg:
        :param count:
        :return:
        """
        if self.activity_role.score < product_cfg.unlock_score:
            raise GameException(TipsInfo.ActivityShopKeys.ActivityShopProductNotUnlock)
        if self.activity_role.coin < product_cfg.cost_num * count:
            raise GameException(TipsInfo.ActivityShopKeys.ActivityShopNeedCostNotEnough)

    @staticmethod
    def check_buy_limit(product_record, product_cfg, count):
        """
        校验限购
        :param product_record:
        :param product_cfg:
        :param count:
        :return:
        """
        if product_record.buy_num + count > product_cfg.limit_times:
            raise GameException(TipsInfo.ActivityShopKeys.ActivityShopOverMaxNum)

    @staticmethod
    def get_award_item_list(product_cfg):
        """
        获得购买道具
        :param product_cfg:
        :return:
        """
        award_item_list = product_cfg.award_list

        return award_item_list

    def purchase_log(self, product_cfg, count):
        """
        埋点
        :return:
        """
        # 兑换券埋点
        from pyshare.game_logs.cross_monopoly_log import CrossMonopolyCoinLog
        cost = product_cfg.cost_num * count
        log_param = LogParam(rid=self.activity_role.role_guid,
                             remark="大富翁商城购买物品",
                             reserve={"ActivityId": self.activity_id,
                                      "ProductId": product_cfg.product_id,
                                      "Count": count,
                                      "Score": self.activity_role.score,
                                      "Cost": cost})
        CrossMonopolyCoinLog.log_game(log_param,
                                      new_val=self.activity_role.coin,
                                      add_value=-cost)


class PuzzleShop(ActivityShopManager):
    """拼图活动商城"""

    def __init__(self, puzzle_role, activity):
        super(PuzzleShop, self).__init__(
            activity_role=puzzle_role,
            shop_cfg_list=PuzzleShopCfgRepository.filter_by_templateid(activity.template_id),
        )
        self.activity = activity
        self.repository = PuzzleRoleRepository

    def reduce_cost(self, product_cfg, count):
        """
        扣除积分
        :param product_cfg:
        :param count:
        :return:
        """
        self.activity_role.score -= product_cfg.cost_num * count
        self.repository.save(self.activity_role)

    def check_is_can_buy(self, product_cfg, count):
        """
        校验是否能购买
        :param product_cfg:
        :param count:
        :return:
        """
        if self.activity_role.score < product_cfg.cost_num * count:
            raise GameException(TipsInfo.ActivityShopKeys.ActivityShopNeedCostNotEnough)

    @staticmethod
    def check_buy_limit(product_record, product_cfg, count):
        """
        校验限购
        :return:
        """
        # 仅校验称号的限购次数
        award_list = product_cfg.award_list
        for award in award_list:
            if award[0] == ItemType.Title:
                if product_record.buy_num + count > 1:
                    raise GameException(TipsInfo.ActivityShopKeys.ActivityShopOverMaxNum)

    @staticmethod
    def get_award_item_list(product_cfg):
        """
        获得购买道具
        :param product_cfg:
        :return:
        """
        award_item_list = product_cfg.award_list

        return award_item_list

    def purchase_log(self, product_cfg, count):
        """
        埋点
        :return:
        """
        # 积分埋点
        PuzzleScoreLog.log_game(self.activity_role.role_guid,
                                self.activity_role.score,
                                -product_cfg.cost_num * count,
                                "商城购买道具消耗积分")

        # 购买事件埋点
        award_item_list = self.get_award_item_list(product_cfg)
        cost = product_cfg.cost_num * count
        for award_item in award_item_list:
            PuzzleLog.purchase_product_log(self.activity_role.role_guid,
                                           self.activity_id,
                                           award_item[0],
                                           award_item[1],
                                           count,
                                           self.activity_role.score + cost,
                                           self.activity_role.score)
